package com.bjy.qa.agent.tester;

import com.alibaba.fastjson.JSONObject;
import com.bjy.qa.agent.enumtype.CatalogType;
import com.bjy.qa.agent.enumtype.RunStatus;
import com.bjy.qa.agent.enumtype.RunningModeStatus;
import com.bjy.qa.agent.exception.BreakException;
import com.bjy.qa.agent.tools.http.Params;
import com.bjy.qa.agent.transport.http.HttpClient;
import com.bjy.qa.agent.transport.mqtt.MqttClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * log工具类，会将运行结果发送到服务端入库
 */
public class LogUtil {
    private final Logger logger = LoggerFactory.getLogger(LogUtil.class);
    public String sessionId = ""; // 当 type=DEBUGGING 需要传入sessionId，服务器收到上报后通过这个 sessionId 发送到对应的 websocket
    public RunningModeStatus type; // 运行类型（DEBUGGING、TESTING）
    public int catalogType; // 分类类型 - 上报日志类型
    public int caseId = 0; // 用例 id
    public String iterationCount = ""; // 迭代次数
    public int resultId = 0; // 运行结果 id

    /**
     * 上报运行结果到
     * @param message
     */
    public void send(JSONObject message) {
        message.put("ctype", catalogType);
        message.put("cid", caseId);
        message.put("ic", iterationCount);
        message.put("rid", resultId);
        if (type.equals(RunningModeStatus.DEBUGGING)) { // 上报 debug 结果
            message.put("sessionId", sessionId); // debug 模式下，需要 sessionId 来区分一个请求，所以要带上 sessionId
            message.put("apiId", caseId); // debug 模式下，下发用例没有携带 appId，所以用 caseId 带下来的，所以上报的时候用 caseId 替换回 apiId
            sendToServerByMqtt(message);
        } else if (type.equals(RunningModeStatus.TESTING)) { // 上报 test 结果
            sendToServer(message);
        }
    }

    /**
     * 上报运行结果到服务端
     * @param message 发送的消息
     */
    private void sendToServer(JSONObject message) {
        message.put("time", new Date());

        try {
            // TODO: 2023/3/18  暂时打印收到的消息，并把消息直接发回服务器，后续改成对应业务
            Params params = new Params();
            message.forEach((key, value) -> {
                params.add(key, value);
            });

            if (catalogType == CatalogType.INTERFACE_TEST_CASE.getValue()) {
                HttpClient.sendLog(params);
            } else if (catalogType == CatalogType.PERFORMANCE_TEST_SCRIPT.getValue()) {
                HttpClient.sendPerfLog(params);
            } else {
                throw new BreakException("未知的 catalogType（分类类型 - 上报日志类型） catalogType: " + catalogType);
            }
        } catch (IllegalArgumentException e) {
            logger.error(e.getMessage());
            // TODO: 2023/3/18 后续遇到错误需要 http 上报到服务器
        }
    }

    /**
     * 通过 mqtt 上报运行结果到服务器
     * @param message 需要发送的消息
     */
    private void sendToServerByMqtt(JSONObject message) {
        try {
            message.put("time", new Date());
            MqttClient.pub(message);
        } catch (Exception e) {
            logger.error(e.getMessage());
            // TODO: 2023/3/18 后续遇到错误需要 http 上报到服务器
        }
    }

    /**
     * 格式化时间
     * @return
     */
    public String getDateToString() {
        SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
        return sf.format(new Date());
    }

    /**
     * 发送运行时长
     * @param totalTime 运行时长
     * @param version 版本号
     */
    public void sendElapsed(int totalTime, String version) {
        JSONObject log = new JSONObject();
        log.put("msg", "elapsed");
        log.put("ver", version);
        log.put("run", totalTime);
        send(log);
    }

    /**
     * 发送普通步骤 log
     * @param status 步骤状态
     * @param desc 步骤描述
     * @param type 步骤类型(等待、休眠)
     * @param detail 步骤详情
     */
    public void sendStepLog(RunStatus status, String desc, String type, String detail) {
        JSONObject log = new JSONObject();
        log.put("msg", "step");
        log.put("desc", desc);
        log.put("type", type);
        log.put("status", status.getValue());
        log.put("log", detail);
        send(log);
    }

    /**
     * 发送性能 log
     * @param packageName 包名
     * @param type 类型
     * @param detail 详情
     */
    public void sendPerLog(String packageName, int type, JSONObject detail) {
        JSONObject log = new JSONObject();
        log.put("msg", "perform");
        log.put("des", packageName);
        log.put("log", detail.toJSONString());
        log.put("status", type);
        send(log);
    }

    /**
     * 发送测试状态
     * @param status 测试状态
     */
    public void sendStatusLog(RunStatus status) {
        JSONObject log = new JSONObject();
        log.put("msg", "status");
        log.put("des", "");
        log.put("type", "");
        log.put("log", "");
        log.put("status", status.getValue());
        send(log);
    }
}